package com.bl.andr.utillib;

import android.support.annotation.NonNull;
import android.text.TextUtils;

import java.math.BigDecimal;
import java.text.DecimalFormat;

/**
 * desc: 运算工具类
 */
public class MathUtil {


    /****
     * 两个数相乘取整(向下取整)
     */
    public static int floor(double v1, double v2) {
        double multi = Math.floor(multiply(v1, v2));
        return (int) multi;
    }


    //限额金额转换
    public static String calculateTheLimit(String money) {
        if (TextUtils.isEmpty(money)) return "";
        double tempMoney = Double.valueOf(money);
        if (tempMoney > 0 && tempMoney < 999999999) {
            return format(money) + "元";
        } else {
            return "无限额";
        }
    }

    //限额金额转换,去除小数部分(万)
    public static String calculateTheLimitW(String money) {
        if (TextUtils.isEmpty(money)) return "";
        double tempMoney = Double.valueOf(money);
        if (10000 > tempMoney && 0 < tempMoney) {
            return "限额" + format(tempMoney, "0") + "元";
        } else if (10000 <= tempMoney && tempMoney < 999999999) {
            return "限额" + format(div(tempMoney, 10000), "0") + "万";
        } else {
            return "无限额";
        }
    }

    // 百分比0~99进1，99~100退1
    public static int doubleToInt(double num) {
        num = num * 100;
        if (num > 0 && num < 99) {
            if (num - (int) num > 0)
                return (int) num + 1;
            else
                return (int) num;
        } else
            return (int) num;
    }

    /**
     * 计算角度
     */
    public static double arccos(double a) {
        double b = 90.0, c0 = 0.0, c1 = 180.0;
        if (a < 1 && a > -1) {
            do {
                if (Math.cos(b * Math.PI / 180) >= a) {
                    c0 = b;
                    b = (c0 + c1) / 2;
                }
                if (Math.cos(b * Math.PI / 180) <= a) {
                    c1 = b;
                    b = (c0 + c1) / 2;
                }
            }
            while (Math.abs(c0 - c1) > 0.00001);
        }
        return b;
    }


    /**
     * 计算利息
     *
     * @param capital 本金
     * @param rate    利率
     * @param day     计息天数
     * @return 利息
     */
    public static double calInterests(double capital, double rate, int day) {
        return capital * rate * day / (365 * 100);
    }

// *************************************************************************
//  对数值格式化，比如 1,000,000.00
// *************************************************************************


    public static String format(double value) {
        return format(String.valueOf(value));
    }

    public static String format(String value) {
        if (EmptyUtil.isEmpty(value)) value = "0.00";
        return format(value, "");
    }


    public static String format(double value, String pattern) {
        return format(String.valueOf(value), pattern);
    }

    /**
     * 格式化给定的字符串
     *
     * @param value   数值
     * @param pattern 格式
     *                ##,##0.00 : 100,000.00
     *                ##,##0    : 100,000
     */
    public static String format(@NonNull String value, String pattern) {
        if (TextUtils.isEmpty(pattern)) pattern = "##,##0.00";
        BigDecimal bigDecimal = new BigDecimal(value);
        DecimalFormat df = new DecimalFormat(pattern);
        return df.format(bigDecimal);
    }


/**
 * Desc:  DecimalFormat 是 NumberFormat 的一个具体子类，用于格式化十进制数字（整数，小数）。
 * DecimalFormat 包含一个模式 和一组符号
 * 符号含义： 0  一个数字，如果位数不足则以 0 填充
 * #  一个数字，不包括 0，要有可能就把数字拉上这个位置
 * .  小数的分隔符的占位符
 * ,  分组分隔符的占位符
 * ;  分隔格式
 * -  缺省负数前缀
 * %  乘以 100 和作为百分比显示
 * ?  乘以 1000 和作为千进制货币符显示；用货币符号代替；如果双写，用国际货币符号代替。
 * 如果出现在一个模式中，用货币十进制分隔符代替十进制分隔符。
 * X  前缀或后缀中使用的任何其它字符，用来引用前缀或后缀中的特殊字符。
 * <p>
 * Creator ling
 * Date:   2017/9/1 0001 09:59
 */
 public  static String format(Object value, String pattern) {
        if (value == null) return "";
        if (TextUtils.isEmpty(pattern)) return String.valueOf(value);
        return new DecimalFormat(pattern).format(value);
    }


// 测试数据
public void test() {
        // 保留小数时按四舍五入的方式做的，
        // 如果需求是截取的小数，则不能直接用此方式，需要先对数字按要求截取后再格式化

        double pi = 3.1415927; //圆周率
        //取一位整数
        System.out.println(new DecimalFormat("0").format(pi));//3
        //取一位整数和两位小数
        System.out.println(new DecimalFormat("0.00").format(pi));//3.14
        //取两位整数和三位小数，整数不足部分以0填补。
        System.out.println(new DecimalFormat("00.000").format(pi));// 03.142
        //取所有整数部分
        System.out.println(new DecimalFormat("#").format(pi)); //3
        //以百分比方式计数，并取两位小数
        System.out.println(new DecimalFormat("#.##%").format(pi));//314.16%

        double a = 1000000000.34555;
        System.out.println(new DecimalFormat("##,##0.00").format(a));// 1,000,000,000.35

        double b = 0.34555;
        System.out.println(new DecimalFormat("##,###.00").format(b));// .35
        System.out.println(new DecimalFormat("##,##0.00").format(b));// 0.35
        System.out.println(new DecimalFormat("##,##0").format(b));// 0
        System.out.println(new DecimalFormat("##,###").format(b));// 0


        long c = 299792458;//光速
        //显示为科学计数法，并取五位小数
        System.out.println(new DecimalFormat("#.#####E0").format(c));//2.99792E8
        //显示为两位整数的科学计数法，并取四位小数
        System.out.println(new DecimalFormat("00.####E0").format(c));//29.9792E7
        //每三位以逗号进行分隔。
        System.out.println(new DecimalFormat(",###").format(c));//299,792,458
        //将格式嵌入文本
        System.out.println(new DecimalFormat("光速大小为每秒,###米。").format(c));
    }



// *************************************************************************
//  关于浮点数运算
// *************************************************************************

    /**
     * @param v1 被除数
     * @param v2 除数
     * @return
     */
    public static double div(double v1, double v2) {
        return div(v1, v2, 2, BigDecimal.ROUND_DOWN);
    }


    /**
     * 提供精确的加法运算。
     *
     * @param v1 被加数
     * @param v2 加数
     * @return 两个参数的和
     */
    public static double add(double v1, double v2) {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.add(b2).doubleValue();
    }


    /**
     * 提供精确的加法运算。
     *
     * @param v 将多个值相加
     * @return 和
     */
    public static double add(double... v) {
        if (v.length <= 0) return 0d;
        if (v.length == 1) return v[0];
        BigDecimal addAll = new BigDecimal(Double.toString(v[0]));
        for (int i = 1; i < v.length; i++) {
            addAll = addAll.add(new BigDecimal(Double.toString(v[i])));
        }
        return addAll.doubleValue();
    }


    /**
     * 提供精确的减法运算。
     *
     * @param v1 被减数
     * @param v2 减数
     * @return 两个参数的差
     */
    public static double sub(double v1, double v2) {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.subtract(b2).doubleValue();
    }

    /**
     * 提供精确的减法运算。
     *
     * @param v 将多个值相减
     * @return 差
     */
    public static double sub(double... v) {
        if (v.length <= 0) return 0d;
        if (v.length == 1) return v[0];
        BigDecimal addAll = new BigDecimal(Double.toString(v[0]));
        for (int i = 1; i < v.length; i++) {
            addAll = addAll.subtract(new BigDecimal(Double.toString(v[i])));
        }
        return addAll.doubleValue();
    }


    /**
     * 提供精确的乘法运算。
     *
     * @param v1 被乘数
     * @param v2 乘数
     */
    public static double multiply(double v1, double v2) {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.multiply(b2).doubleValue();
    }

    /**
     * 提供精确的乘法运算。
     *
     * @param v 将多个值相乘
     */
    public static double multiply(double... v) {
        if (v.length <= 0) return 0d;
        if (v.length == 1) return v[0];
        BigDecimal addAll = new BigDecimal(Double.toString(v[0]));
        for (int i = 1; i < v.length; i++) {
            addAll = addAll.multiply(new BigDecimal(Double.toString(v[i])));
        }
        return addAll.doubleValue();
    }


    /**
     * 提供（相对）精确的除法运算。
     * 当发生除不尽的情况时，由scale参数指 定精度，以后的数字根据roundMode舍入。
     *
     * @param v1        被除数
     * @param v2        除数
     * @param scale     表示表示需要精确到小数点以后几位。
     * @param roundMode 舍入模式
     *                  {@link BigDecimal#ROUND_UP}
     *                  {@link BigDecimal#ROUND_DOWN}
     *                  {@link BigDecimal#ROUND_HALF_DOWN}
     *                  {@link BigDecimal#ROUND_HALF_UP}
     * @return 两个参数的商
     */
    public static double div(double v1, double v2, int scale, int roundMode) {
        if (scale < 0) {
            throw new IllegalArgumentException(
                    "The scale must be a positive integer or zero");
        }
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.divide(b2, scale, roundMode).doubleValue();
    }


// *************************************************************************
// 浮点数精度处理
// *************************************************************************

    /**
     * 截取两位小数
     */
    public static double roundDown(double v) {
        return roundDown(v, 2);
    }

    /**
     * 截取
     * 接近0的舍入方式
     *
     * @param v     操作对象
     * @param scale 保留小数的位数
     */
    public static double roundDown(double v, int scale) {
        return round(v, scale, BigDecimal.ROUND_DOWN);
    }


    /**
     * 提供精确的小数位保留处理。
     * 采用除法的方式
     *
     * @param v         需要保留位数的数字
     * @param scale     小数点后保留几位
     * @param roundMode 保留的模式
     * @return 舍入后的结果
     */
    public static double round(double v, int scale, int roundMode) {
        if (scale < 0) {
            throw new IllegalArgumentException(
                    "The scale must be a positive integer or zero");
        }
        BigDecimal b = new BigDecimal(Double.toString(v));
        BigDecimal one = new BigDecimal("1");
        return b.divide(one, scale, roundMode).doubleValue();
    }

    /**
     * 保留几位小数
     *
     * @param v         原始数据
     * @param scale     小数位数
     * @param roundMode 舍入规则
     */
    public static double round2(double v, int scale, int roundMode) {
        BigDecimal bigDecimal = new BigDecimal(Double.toString(v));
        return bigDecimal.setScale(scale, roundMode).doubleValue();
    }


    /**
     * 对一个数进行下取整
     * 上取整 ceil
     * 四舍五入取整 round
     *
     * @param v 1.5 ==>1.0; -1.2 ==>> -2.0
     */
    public static double floor(double v) {
        return Math.floor(v);
    }

}
